package com.knowswift.issues.controller;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.knowswift.common.bean.issue.po.Issue;
import com.knowswift.common.bean.issue.po.MonitorRecord;
import com.knowswift.common.bean.issue.vo.*;
import com.knowswift.common.bean.project.po.Module;
import com.knowswift.common.bean.issue.po.MonitorDevice;
import com.knowswift.common.bean.project.po.Project;
import com.knowswift.common.bean.project.vo.ModulePermissionVO;
import com.knowswift.common.bean.project.vo.ModuleVO;
import com.knowswift.common.bean.project.vo.ProjectLimit;
import com.knowswift.common.common.*;
import com.knowswift.common.utils.WrappedBeanCopier;
import com.knowswift.security.account.User;
import com.knowswift.security.account.UserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

@RestController
@RequestMapping("/app/monitor/")
public class AppMonitorController extends AbstractController {
    @PreAuthorize("@userService.checkAuthority('editMonitor')")
    @PostMapping("/device/save")
    public BaseResponse saveDevice(@RequestBody @Validated SaveMonitorDeviceParam param) {
        int count = monitorDeviceService.count(new LambdaQueryWrapper<MonitorDevice>().eq(MonitorDevice::getSerialNumber, param.getSerialNumber()));
        Assert.isFalse(count != 0, "设备序列号已存在");

        validateDeviceData(param.getModuleName(), param.getProjectName(), param.getAreaName());
        MonitorDevice monitorDevice = WrappedBeanCopier.copyProperties(param, MonitorDevice.class);
        if (param.getAcceptPosition() == null) {
            param.setAcceptPosition(false);
        }
        monitorDeviceService.save(monitorDevice);
        return BaseResponse.success();
    }

    @PreAuthorize("@userService.checkAuthority('editMonitor')")
    @PostMapping("/device/update")
    public BaseResponse updateDevice(@RequestBody @Validated UpdateMonitorDeviceParam param) {
        validateDeviceData(param.getModuleName(), param.getProjectName(), param.getAreaName());
        MonitorDevice monitorDevice = WrappedBeanCopier.copyProperties(param, MonitorDevice.class);
        Assert.isTrue(monitorDeviceService.updateById(monitorDevice), "设备不存在");
        return BaseResponse.success();
    }

    @PostMapping("/device/get")
//    @PreAuthorize("@userService.checkAuthority('monitorDevices')")
    public BaseResponse get(@RequestBody MonitorDeviceVO param, Authentication authentication) {
        String serialNumber = param.getSerialNumber();
        Assert.isTrue(serialNumber != null, "序列号不可为空");
        LambdaQueryWrapper<MonitorDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MonitorDevice::getSerialNumber, serialNumber);
        MonitorDevice monitorDevice = monitorDeviceService.getOne(wrapper);
        if (monitorDevice == null) {
            return BaseResponse.success();
        }
        MonitorDeviceAlertCountVO vo = WrappedBeanCopier.copyProperties(monitorDevice, MonitorDeviceAlertCountVO.class);

        User user = (User) authentication.getPrincipal();

        boolean allIssues = UserService.checkAuthority(user, "allIssues");
        boolean ownIssues = UserService.checkAuthority(user, "ownIssues");
        boolean projectIssues = UserService.checkAuthority(user, "projectIssues");
        Page<ModuleVO> page = new Page<>(1L, 9999L);
        boolean hasPermission = false;


        if (!allIssues && !ownIssues && projectIssues) {
            // 根据模块和项目判断
            Page<ModulePermissionVO> modulePage = modulePermissionService.getBaseMapper().getByUserIdPage(user.getUserId(), page);
            modulePermissionService.concatData(modulePage.getRecords());
            for (ModulePermissionVO modulePermissionVO : modulePage.getRecords()) {
                if (modulePermissionVO.getModuleName().equals(monitorDevice.getModuleName())) {
                    List<ProjectLimit> projectLimits = WrappedBeanCopier.JSONArrayToList(modulePermissionVO.getProjects(), ProjectLimit.class);
                    for (ProjectLimit project : projectLimits) {
                        if (project.getProjectName().equals(monitorDevice.getProjectName())) {
                            hasPermission = true;
                            break;
                        }
                    }
                    break;
                }
            }
        }
        if (allIssues) {
            hasPermission = true;
        }
        Assert.isTrue(hasPermission, "没有权限访问数据");
        handleDeviceVO(vo, user);

        LambdaQueryWrapper<MonitorRecord> monitorRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getDeviceId, vo.getDeviceId());
        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getDeviceStatus, GlobalProperty.DEVICE_STATUS_ALERT);

        int count = monitorRecordService.count(monitorRecordLambdaQueryWrapper);
        vo.setAlertCount(count);

        // 处理显示数据
        return BaseResponse.success(vo);
    }

    @PostMapping("/device/monitorMap")
    public BaseResponse monitorMap(@RequestBody HashMap<String, String> map, Authentication authentication) {
        String projectName = map.get("projectName");
        String moduleName = map.get("moduleName");
        User user = (User) authentication.getPrincipal();
        if (!"ROLE_ADMIN".equals(user.getRole()) && !UserService.checkAuthority(user, "issueView")){
            return BaseResponse.success(new MonitorDeviceCountVO());
        }

        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);
        MonitorDeviceCountVO monitorDeviceCountVO = monitorDeviceService.countDevice(moduleName,projectName, moduleProjects, user);
        return BaseResponse.success(monitorDeviceCountVO);
    }

    @PostMapping("/device/alertCount")
    public BaseResponse alertCount(@RequestBody MonitorAlertCountParam param, Authentication authentication) {
        User user = (User) authentication.getPrincipal();
        if (!"ROLE_ADMIN".equals(user.getRole()) && !UserService.checkAuthority(user, "issueView")){
            return BaseResponse.success();
        }

        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);
        Object monitorAlertCountVOS = monitorRecordService.alertCount(param, moduleProjects);
        return BaseResponse.success(monitorAlertCountVOS);
    }

    @PostMapping("/device/monitorIssues")
    public BaseResponse monitorIssues(@RequestBody PageParam<MonitorDeviceVO> param, Authentication authentication) {
        Page<IssueVO> page = new Page<>(param.getPageNo(), param.getPageSize());
        MonitorDeviceVO condition = param.getCondition();
        User user = (User) authentication.getPrincipal();

        MonitorDevice monitorDevice = monitorDeviceService.getById(condition.getDeviceId());
        Assert.isTrue(!ObjectUtil.isEmpty(monitorDevice), "id不可为空");

        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);
        page = issueService.getBaseMapper().getRecordsByModule(monitorDevice.getModuleName(), monitorDevice.getProjectName(), moduleProjects, monitorDevice.getDeviceId(), page);

        return BaseResponse.success(page);
    }

    @PostMapping("/device/modules")
//    @PreAuthorize("@userService.checkAuthority('allIssues','ownIssues','projectIssues')")
//    @AopLog(name = "模块列表", platform = "管理后台")
    public BaseResponse modules(@AuthenticationPrincipal User user, @RequestBody PageParam<MonitorDeviceVO> param) {
//        Page<MonitorDevice> page = new Page<>(param.getPageNo(), param.getPageSize());
//        MonitorDeviceVO condition = param.getCondition();
//
//        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);
//
//        page =  monitorDeviceService.dropDownList("module_name",condition, moduleProjects,page);
//
//        return BaseResponse.success(page);
        Page<Module> page = new Page<>(param.getPageNo(), param.getPageSize());
        boolean allIssues = UserService.checkAuthority(user, "allIssues");
        boolean ownIssues = UserService.checkAuthority(user, "ownIssues");
        boolean projectIssues = UserService.checkAuthority(user, "projectIssues");
        if (!allIssues && !ownIssues && projectIssues) {
            Page<ModuleVO> page1 = new Page<>(param.getPageNo(), param.getPageSize());
            Page<ModulePermissionVO> voPage = modulePermissionService.getBaseMapper().getByUserIdPage(user.getUserId(), page1);
            modulePermissionService.concatData(voPage.getRecords());
            return BaseResponse.success(voPage);
        }
        page = moduleService.lambdaQuery().select(Module::getModuleName, Module::getProjects).orderByAsc(Module::getModuleOrder).page(page);
        return BaseResponse.success(page);
    }

    @PostMapping("/device/projects")
    public BaseResponse projects(@AuthenticationPrincipal User user, @RequestBody PageParam<MonitorDeviceVO> param) {
        Page<MonitorDevice> page = new Page<>(param.getPageNo(), param.getPageSize());
        MonitorDeviceVO condition = param.getCondition();

        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);

        page =  monitorDeviceService.dropDownList("project_name",condition, moduleProjects,page);

        return BaseResponse.success(page);
    }

    @PostMapping("/device/areas")
    public BaseResponse areas(@AuthenticationPrincipal User user, @RequestBody PageParam<MonitorDeviceVO> param) {
        Page<MonitorDevice> page = new Page<>(param.getPageNo(), param.getPageSize());
        MonitorDeviceVO condition = param.getCondition();

        List<String> moduleProjects = monitorRecordService.getModuleProjects(user);

        page =  monitorDeviceService.dropDownList("area_name",condition, moduleProjects,page);

        return BaseResponse.success(page);
    }

//    @PostMapping("/device/modules")
//    public BaseResponse modules(@AuthenticationPrincipal User user, @RequestBody ModuleVO param) {
//        Page<ModuleVO> page = new Page<>(param.getPageNo(), param.getPageSize());
//        boolean allIssues = UserService.checkAuthority(user, "allIssues");
//        boolean ownIssues = UserService.checkAuthority(user, "ownIssues");
//        boolean projectIssues = UserService.checkAuthority(user, "projectIssues");
//        if (!allIssues && !ownIssues && projectIssues) {
//            Page<ModulePermissionVO> voPage = modulePermissionService.getBaseMapper().getByUserIdPage(user.getUserId(), page);
//            modulePermissionService.concatData(voPage.getRecords());
//            return BaseResponse.success(voPage);
//        }
//
//        page = moduleService.getBaseMapper().getList(param.getKeyword(), 0, page);
//        return BaseResponse.success(page);
//    }
//
//    @PostMapping("/device/projects")
//    public BaseResponse projects(@RequestBody HashMap<String, String> map) {
//        String moduleName = map.get("moduleName");
//
//        LambdaQueryWrapper<MonitorRecord> monitorRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getModuleName, moduleName);
//        monitorRecordLambdaQueryWrapper.groupBy(MonitorRecord::getProjectName);
//        monitorRecordLambdaQueryWrapper.select(MonitorRecord::getProjectName);
//
//        List<MonitorRecord> monitorRecords = monitorRecordService.list(monitorRecordLambdaQueryWrapper);
//
//        return BaseResponse.success(monitorRecords);
//    }
//
//    @PostMapping("/device/areas")
//    public BaseResponse areas(@RequestBody HashMap<String, String> map) {
//        String moduleName = map.get("moduleName");
//        String projectName = map.get("projectName");
//
//        LambdaQueryWrapper<MonitorRecord> monitorRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getProjectName, projectName);
//        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getModuleName, moduleName);
//        monitorRecordLambdaQueryWrapper.groupBy(MonitorRecord::getAreaName);
//        monitorRecordLambdaQueryWrapper.select(MonitorRecord::getAreaName);
//
//        List<MonitorRecord> monitorRecords = monitorRecordService.list(monitorRecordLambdaQueryWrapper);
//
//        return BaseResponse.success(monitorRecords);
//    }

    @PostMapping("/device/monitorObjects")
    public BaseResponse monitorObjects(@RequestBody HashMap<String, String> map) {
        String moduleName = map.get("moduleName");
        String projectName = map.get("projectName");
        String areaName = map.get("areaName");

        LambdaQueryWrapper<MonitorRecord> monitorRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getProjectName, projectName);
        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getModuleName, moduleName);
        monitorRecordLambdaQueryWrapper.eq(MonitorRecord::getAreaName, areaName);
        monitorRecordLambdaQueryWrapper.groupBy(MonitorRecord::getMonitorObject);
        monitorRecordLambdaQueryWrapper.select(MonitorRecord::getMonitorObject);

        List<MonitorRecord> monitorRecords = monitorRecordService.list(monitorRecordLambdaQueryWrapper);

        return BaseResponse.success(monitorRecords);
    }

    private void handleDeviceVO(MonitorDeviceVO vo, User user) {
        vo.setOnline(true);
        if (vo.getLastMessageTime() == null) {
            vo.setOnline(false);
        } else {
            // over 2 hours, regard the device as offline
            if (Duration.between(vo.getLastMessageTime(), LocalDateTime.now()).toHours() >= 2) {
                vo.setOnline(false);
            }
        }

        vo.setIsEdit(true);
        vo.setIsElectric(true);
        // 权限过滤
        if (!UserService.checkAuthority(user, "electricMonitor")) {
            vo.setVoltage(null);
            vo.setBattery(null);
            vo.setElectric(null);
            vo.setIsElectric(false);
        }

        if (!UserService.checkAuthority(user,"editMonitor")){
            vo.setIsEdit(false);
        }

        if (!UserService.checkAuthority(user, "errorMonitor")) {
            if (vo.getDeviceStatus().equals(GlobalProperty.DEVICE_STATUS_ERROR)) {
                vo.setDeviceStatus(GlobalProperty.DEVICE_STATUS_NORMAL);
            }
        }
    }

    private void validateDeviceData(String moduleName, String projectName, String areaName) {
        Module module = moduleService.getOne(new LambdaQueryWrapper<Module>().eq(Module::getModuleName, moduleName), false);
        Assert.isTrue(module != null, "模块不存在");

        List<Project> projects = WrappedBeanCopier.JSONArrayToList(module.getProjects(), Project.class);
        boolean existProject = false;
        for (Project project : projects) {
            if (project.getProjectName().equals(projectName)) {
                existProject = true;
                break;
            }
        }
        Assert.isTrue(existProject, "项目不存在");

//        List<String> areas = issueService.listObjs(new LambdaQueryWrapper<Issue>()
//                        .select(Issue::getIssueArea)
//                        .eq(Issue::getModuleName, moduleName)
//                        .eq(Issue::getProjectName, projectName)
//                        .orderByDesc(Issue::getReportTime)
//                , Object::toString);
//        Assert.isTrue(areas.contains(areaName), "区域不存在");
    }
}
